grammar Hawera;

options {
  language = Java;
}

@header {
  package cz.cvut.fit.crhonjar.mi.run.hawera.parser;
}

@lexer::header {
  package cz.cvut.fit.crhonjar.mi.run.hawera.parser;  
}

programFile: imports? (classDeclaration | statement)* EOF;

//imports

imports :
        (IMPORT STRING)+
        ;

// classDeclaration

classDeclaration :
                 CLASS IDENT (INHERIT_OP IDENT)?
                 START_BLOCK (functionDeclaration | classVariable | classConst )+ END_BLOCK
                 ;
                 
// functionDeclaration

functionDeclaration :
                    accessModentifier?
                    STATIC?
                    IDENT
                      LPAR functionDeclarationParameters? PPAR
                      block
                    ;
                    
block :
      START_BLOCK
        statement+
      END_BLOCK
      ;
                    
functionDeclarationParameters :
                    (IDENT (SEPARATOR IDENT)*)
                    ;
                    

classVariable :
               accessModentifier? STATIC? IDENT (ASSIGN_OP expression)? ENDSTATEMENT
               ;
               
classConst :
             accessModentifier?  STATIC? constantStatement
             ;

accessModentifier :
                    PRIVATE 
                  | PUBLIC
                  | PROTECTED
                  ;
                  

// statements

statement :
            assignmentStatement
          | constantStatement
          | ifStatement
          | whileStatement
          | forStatement
          | foreachStatement
          | returnStatement
          | breakStatement
          | continueStatement
          | functionStatement
          | emptyStatement
          ;
          
functionStatement :
          functionCall ENDSTATEMENT
          ;
          
emptyStatement :
          ENDSTATEMENT
          ;
          
functionCall :
          IDENT 
          (
            LPAR functionParameters? PPAR
          )?
          (
            CLASS_ACCESSOR 
            (
                IDENT (LPAR functionParameters? PPAR)? 
              | CONST_IDENTIFIER
            )
          )* 
          FUNCTION_CALL_END
          ;
          
functionParameters :
          (expression(SEPARATOR expression)*)
          ;
          
assignmentStatement :
            IDENT ASSIGN_OP expression (WHEN expression)? ENDSTATEMENT 
            ;
            
constantStatement :
            CONST_IDENTIFIER ASSIGN_OP expression ENDSTATEMENT
            ;
            
ifStatement :
            IF
              LPAR expression PPAR
            block
            (
              ELSE IF
                LPAR expression PPAR
                block
            )*
            (
              ELSE 
              block
            )?
            ;


whileStatement :
          WHILE 
            LPAR expression PPAR 
            block
          ;
          

forStatement : 
          FOR 
          LPAR
            IDENT ASSIGN_OP expression SEPARATOR
            expression SEPARATOR
            IDENT ASSIGN_OP expression 
          PPAR
          block
          ;
          
foreachStatement :
          FOREACH
          LPAR
            IDENT ASSIGN_OP expression 
          PPAR
          block
          ;
          
returnStatement :
          RETURN expression? ENDSTATEMENT
          ;
          
breakStatement :
          BREAK ENDSTATEMENT
          ;
          
continueStatement :
          CONTINUE ENDSTATEMENT
          ;
//expression

instanceOfTerm :
        IDENT INSTANCEOF IDENT
        ;

term :
        NUMBER
      | FLOAT
      | STRING
      | BOOLEAN
      | instanceOfTerm
      | IDENT
      | functionCall
      | CONST_IDENTIFIER
      | PPAR expression PPAR
      ;
pow :
      term (POW term)*
    ;
    
unary :
        (NOT | MINUS | PLUS)* pow
      ;
      
      
mult :
       unary ((MUL | DIV | MOD) unary)*
     ;
        
add :
      mult ((PLUS | MINUS) mult)*
    ;
        
relation :
           add ((EQ | NEQ | LT | GT | LE | GE) add)?
         ;
         
expression :
             relation ((AND | OR | XOR) relation)*
           ;

// keywords

CLASS : 'class' ;
WHEN : 'when' ;
IF : 'if' ;
ELSE : 'else' ;
WHILE : 'while' ;
FOR : 'for' ;
FOREACH : 'foreach' ;
RETURN : 'return' ;
BREAK : 'break' ;
CONTINUE : 'continue' ;
IMPORT : 'import' ;

// modifiers

PRIVATE : 'private' ;
PUBLIC : 'public' ;
PROTECTED : 'protected' ;

STATIC : 'static' ;


// misc

FLOAT : DIGIT* '.' DIGIT* (('e'|'E') MINUS? DIGIT+)? ;
NUMBER : DIGIT+ ;  
STRING : '"' .* '"' ;
BOOLEAN : TRUE | FALSE ;
WS : (' ' | '\t' | '\n' | '\r' | '\f')+ {$channel = HIDDEN;};
IDENT : LETTER (LETTER | DIGIT)* ;
CONST_IDENTIFIER : UPPERCASE_LETTER+ ;
COMMENT : '//' .* ('\r' | '\n') {$channel = HIDDEN;};
START_BLOCK : '{' ;
END_BLOCK : '}' ;
LPAR : '(' ;
PPAR : ')' ;
ASSIGN_OP : '<-' ;
SEPARATOR : ',' ;
CLASS_ACCESSOR : '->' ;
ENDSTATEMENT : ';' ;
INHERIT_OP : '~' ;
LBRACKED : '[' ;
PBRACKED : ']' ;
FUNCTION_CALL_END : '#';
INSTANCEOF : '@' ;

// expression operators
// binary
PLUS : '+';
MINUS : '-';
MUL : '*';
DIV : '/';
MOD : '%';
POW : '^';
// logical
AND : '&&';
OR : '||';
XOR : '^^';
// relation
EQ : '==';
NEQ : '!=';
GT : '>';
LT : '<';
GE : '>=';
LE : '<=';
// unary
NOT : '!';


fragment LETTER : ('a'..'z');
fragment UPPERCASE_LETTER : ('A'..'Z');
fragment DIGIT  : ('0'..'9');

fragment TRUE : 'TRUE' ;
fragment FALSE : 'FALSE' ;

